
//Instruction set type:	thumb

#include <stdint.h>

#ifndef insn_getbit
#define insn_getbit(insn, off, num) ((insn >> off) & ((1 << num) - 1))
#endif

extern void t_asr_imm_zero(uint32_t*R,...);
extern void t_ror(uint32_t*R,...);
extern void t_lsr(uint32_t*R,...);
extern void t_lsl(uint32_t*R,...);
extern void t_orr(uint32_t*R,...);
extern void t_mul(uint32_t*R,...);
extern void t_tst(uint32_t*R,...);
extern void t_bic(uint32_t*R,...);
extern void t_eor(uint32_t*R,...);
extern void t_cmn(uint32_t*R,...);
extern void t_cmp(uint32_t*R,...);
extern void t_asr(uint32_t*R,...);
extern void t_mvn(uint32_t*R,...);
extern void t_and(uint32_t*R,...);
extern void t_rsb(uint32_t*R,...);
extern void t_sbc(uint32_t*R,...);
extern void t_rev(uint32_t*R,...);
extern void t_revsh(uint32_t*R,...);
extern void t_rev16(uint32_t*R,...);
extern void t_lsr_imm_zero(uint32_t*R,...);
extern void t_adc(uint32_t*R,...);
extern void t_bx(uint32_t*R,...);
extern void t_blx(uint32_t*R,...);
extern void t_sub_sp(uint32_t*R,...);
extern void t_add_sp(uint32_t*R,...);
extern void t_mov(uint32_t*R,...);
extern void t_ble(uint32_t*R,...);
extern void t_bkpt(uint32_t*R,...);
extern void t_svc(uint32_t*R,...);
extern void t_bgt(uint32_t*R,...);
extern void t_beq(uint32_t*R,...);
extern void t_blt(uint32_t*R,...);
extern void t_bmi(uint32_t*R,...);
extern void t_bne(uint32_t*R,...);
extern void t_add(uint32_t*R,...);
extern void t_bcs(uint32_t*R,...);
extern void t_bpl(uint32_t*R,...);
extern void t_bcc(uint32_t*R,...);
extern void t_bvs(uint32_t*R,...);
extern void t_bls(uint32_t*R,...);
extern void t_bge(uint32_t*R,...);
extern void t_bvc(uint32_t*R,...);
extern void t_bhi(uint32_t*R,...);
extern void t_push(uint32_t*R,...);
extern void t_ldrsh(uint32_t*R,...);
extern void t_str(uint32_t*R,...);
extern void t_strb(uint32_t*R,...);
extern void t_pop(uint32_t*R,...);
extern void t_ldrsb(uint32_t*R,...);
extern void t_ldrb(uint32_t*R,...);
extern void t_ldrh(uint32_t*R,...);
extern void t_add_imm(uint32_t*R,...);
extern void t_sub_imm(uint32_t*R,...);
extern void t_sub(uint32_t*R,...);
extern void t_strh(uint32_t*R,...);
extern void t_ldr(uint32_t*R,...);
extern void t_strb_imm(uint32_t*R,...);
extern void t_stm(uint32_t*R,...);
extern void t_str_imm(uint32_t*R,...);
extern void t_str_sp(uint32_t*R,...);
extern void t_strh_imm(uint32_t*R,...);
extern void t_b(uint32_t*R,...);
extern void t_adr(uint32_t*R,...);
extern void t_ldr_imm(uint32_t*R,...);
extern void t_cmp_imm(uint32_t*R,...);
extern void t_ldm(uint32_t*R,...);
extern void t_ldrb_imm(uint32_t*R,...);
extern void t_mov_imm(uint32_t*R,...);
extern void t_asr_imm(uint32_t*R,...);
extern void t_ldrh_imm(uint32_t*R,...);
extern void t_lsl_imm(uint32_t*R,...);
extern void t_lsr_imm(uint32_t*R,...);
extern void t_bl(uint32_t*R,...);


void thumb_exec(uint32_t *R, uint32_t insn)
{
    uint32_t maskValue = insn & 0xFFC0;
    if (maskValue == 0x1000)
    { // asr
        t_asr_imm_zero(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x41C0)
    { // ror
        t_ror(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x40C0)
    { // lsr
        t_lsr(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4080)
    { // lsl
        t_lsl(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4300)
    { // orr
        t_orr(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4340)
    { // mul
        t_mul(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4200)
    { // tst
        t_tst(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4380)
    { // bic
        t_bic(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4040)
    { // eor
        t_eor(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x42C0)
    { // cmn
        t_cmn(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4280)
    { // cmp
        t_cmp(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4100)
    { // asr
        t_asr(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4240)
    { // neg
        t_mvn(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4000)
    { // and
        t_and(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4240)
    { // rsb
        t_rsb(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4180)
    { // sbc
        t_sbc(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0xBA00)
    { // rev
        t_rev(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0xBAC0)
    { // revsh
        t_revsh(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0xBA40)
    { // rev16
        t_rev16(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x800)
    { // lsr
        t_lsr_imm_zero(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else if (maskValue == 0x4140)
    { // adc
        t_adc(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3));
    }
    else
    {
        uint32_t maskValue = insn & 0xFF80;
        if (maskValue == 0x4700)
        { // bx
            t_bx(R, insn_getbit(insn, 3, 4));
        }
        else if (maskValue == 0x4780)
        { // blx
            t_blx(R, insn_getbit(insn, 3, 4));
        }
        else if (maskValue == 0xB080)
        { // sub
            t_sub_sp(R, insn_getbit(insn, 0, 7));
        }
        else if (maskValue == 0xB000)
        { // add
            t_add_sp(R, 13, insn_getbit(insn, 0, 7));
        }
        else
        {
            uint32_t maskValue = insn & 0xFF00;
            if (maskValue == 0x4600)
            { // mov
                t_mov(R, insn_getbit(insn, 0, 3) + insn_getbit(insn, 7, 1) * 8, insn_getbit(insn, 3, 4));
            }
            else if (maskValue == 0xDD00)
            { // ble
                t_ble(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xBE00)
            { // bkpt
                t_bkpt(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xDF00)
            { // svc
                t_svc(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xDC00)
            { // bgt
                t_bgt(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0x4500)
            { // cmp
                t_cmp(R, insn_getbit(insn, 0, 3) + insn_getbit(insn, 7, 1) * 8, insn_getbit(insn, 3, 4));
            }
            else if (maskValue == 0xD000)
            { // beq
                t_beq(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xDB00)
            { // blt
                t_blt(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD400)
            { // bmi
                t_bmi(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD100)
            { // bne
                t_bne(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0x4400)
            { // add
                t_add(R, insn_getbit(insn, 0, 3) + insn_getbit(insn, 7, 1) * 8, insn_getbit(insn, 0, 3) + insn_getbit(insn, 7, 1) * 8, insn_getbit(insn, 3, 4));
            }
            else if (maskValue == 0xD200)
            { // bcs
                t_bcs(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD500)
            { // bpl
                t_bpl(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD300)
            { // bcc
                t_bcc(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD600)
            { // bvs
                t_bvs(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD900)
            { // bls
                t_bls(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xDA00)
            { // bge
                t_bge(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD700)
            { // bvc
                t_bvc(R, insn_getbit(insn, 0, 8));
            }
            else if (maskValue == 0xD800)
            { // bhi
                t_bhi(R, insn_getbit(insn, 0, 8));
            }
            else
            {
                uint32_t maskValue = insn & 0xFE00;
                if (maskValue == 0xB400)
                { // push
                    t_push(R, insn_getbit(insn, 0, 8), insn_getbit(insn, 8, 1));
                }
                else if (maskValue == 0x5E00)
                { // ldrsh
                    t_ldrsh(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5000)
                { // str
                    t_str(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5400)
                { // strb
                    t_strb(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0xBC00)
                { // pop
                    t_pop(R, insn_getbit(insn, 0, 8), insn_getbit(insn, 8, 1));
                }
                else if (maskValue == 0x5600)
                { // ldrsb
                    t_ldrsb(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5C00)
                { // ldrb
                    t_ldrb(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x1800)
                { // add
                    t_add(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5A00)
                { // ldrh
                    t_ldrh(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x1C00)
                { // add
                    t_add_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x1E00)
                { // sub
                    t_sub_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x1A00)
                { // sub
                    t_sub(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5200)
                { // strh
                    t_strh(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else if (maskValue == 0x5800)
                { // ldr
                    t_ldr(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 3));
                }
                else
                {
                    uint32_t maskValue = insn & 0xF800;
                    if (maskValue == 0x7000)
                    { // strb
                        t_strb_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0xC000)
                    { // stm
                        t_stm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x6000)
                    { // str
                        t_str_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x9000)
                    { // str
                        t_str_sp(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x3000)
                    { // add
                        t_add_imm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x3800)
                    { // sub
                        t_sub_imm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x8000)
                    { // strh
                        t_strh_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0xE000)
                    { // b
                        t_b(R, insn_getbit(insn, 0, 11));
                    }
                    else if (maskValue == 0xA000)
                    { // adr
                        t_adr(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x9800)
                    { // ldr
                        t_ldr_imm(R, insn_getbit(insn, 0, 8), 13, insn_getbit(insn, 0, 8) * 4);
                    }
                    else if (maskValue == 0x4800)
                    { // ldr
                        t_ldr_imm(R, insn_getbit(insn, 0, 8), 15, insn_getbit(insn, 0, 8) * 4);
                    }
                    else if (maskValue == 0x6800)
                    { // ldr
                        t_ldr_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x2800)
                    { // cmp
                        t_cmp_imm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0xC800)
                    { // ldm
                        t_ldm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0xA800)
                    { // add
                        t_add_sp(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x7800)
                    { // ldrb
                        t_ldrb_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x2000)
                    { // mov
                        t_mov_imm(R, insn_getbit(insn, 8, 3), insn_getbit(insn, 0, 8));
                    }
                    else if (maskValue == 0x1000)
                    { // asr
                        t_asr_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x8800)
                    { // ldrh
                        t_ldrh_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x0)
                    { // lsl
                        t_lsl_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0x800)
                    { // lsr
                        t_lsr_imm(R, insn_getbit(insn, 0, 3), insn_getbit(insn, 3, 3), insn_getbit(insn, 6, 5));
                    }
                    else if (maskValue == 0xF000)
                    { // bl
                        t_bl(R, insn_getbit(insn, 0, 10));
                    }
                };
            };
        };
    };
}; //Instruction set type:	arm
